#include "xmppcore/negotiant.h"
#include "xmppcore/stream.h"
#include "xmppcore/streamfeatures.h"
#include "xmppcore/connector.h"

namespace yoohoo_xmppcore {

Negotiant::Negotiant(Connector* connector, QObject* parent) : _connector(connector), QObject(parent) {
	_negotiationState = None;
	_streamFeatures = 0;
	connect(_connector, SIGNAL(received(QString)), this, SLOT(connectorReceived(QString)));
}

Negotiant::~Negotiant() {
	delete _streamFeatures;
}

void Negotiant::negotiate() {
	sendIntialStream();
}

void Negotiant::write(const QString& xml) {
	_connector->write(xml);
	emit written(xml);
}

StreamFeatures* Negotiant::streamFeatures() {
	return _streamFeatures;
}

void Negotiant::registerStreamFeature(StreamFeature* streamFeature) {
	_streamFeatures->registerSupportedStreamFeature(streamFeature);
}

void Negotiant::connectorReceived(QString xml) {
	if (xml.startsWith("<stream:error>")) // stream error will processed by 'Connection'
		return;

	if (_negotiationState == InitialStreamSent) {
		processInitialStream(xml);
	} else if (_negotiationState == InitialStreamReceived) {
		processStreamFeatures(xml);

		_negotiationState = NogotiationDone;
		emit done(_streamFeatures);
	}
}

void Negotiant::processInitialStream(QString& xml) {
	if (_negotiationState != InitialStreamSent) {
		qWarning("Illegal negotiation state[%d], can't process received xml", _negotiationState);

		return;
	}

	Stream stream;
	if (!stream.fromXml(xml)) {
		emit negotiationError(UnknownNegotiationProtocolError);
		return;
	}

	if (stream.from() == 0 || (stream.from()->toString() != _connector->server()->host())) {
		emit negotiationError(UnknownNegotiationHostError);
	}

	_negotiationState = InitialStreamReceived;
}

void Negotiant::processStreamFeatures(QString& xml) {
	if (_negotiationState != InitialStreamReceived) {
		qWarning("Illegal negotiation state[%d], can't process received xml", _negotiationState);

		return;
	}

	if (!_streamFeatures->matches(xml) || !_streamFeatures->fromXml(xml)) {
		emit negotiationError(UnknownNegotiationProtocolError);
		return;
	}

	_negotiationState = StreamFeaturesReceived;
}

void Negotiant::sendIntialStream() {
	qDebug("Negotiant::sendInitialStream: Sending initial stream");

	JabberId to;;
	to.setDomain(_connector->server()->host());

	Stream stream;
	stream.setTo(to);

	QString initialStreamXml = stream.toXml();
	_negotiationState = InitialStreamSent;
	write(initialStreamXml);
}


}
